#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <filesystem>
// #include "util.hpp"
#include <mutex>
#include <memory>
#include <unordered_map>
#include <atomic>
#include <sys/types.h>
#include <unistd.h>

namespace LogModule_ns
{
    // using namespace util_ns;

    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void LogSync(const std::string &message) = 0;
    };
    class ConsoleStrategy : public LogStrategy
    {
    public:
        void LogSync(const std::string &message) override final
        {
            std::lock_guard<std::mutex> lock(_mtx);
            std::cout << message << std::endl;
        }

    private:
        std::mutex _mtx;
    };

    static const std::string default_path = "./temp/";
    static const std::string default_file = "default.log";
    static const std::string gsep = "\r\n";

    class FileStrategy : public LogStrategy
    {
    public:
        // 给出指定的文件，默认在./temp路径打日志
        FileStrategy(const std::string &file = default_file, const std::string &path = default_path)
            : _file_name(file), _path(path)
        {
            // 鲁棒性
            if (_path.back() != '/')
                _path += '/';
            _file = _path + _file_name;

            // 判断是否存在目录
            if (!std::filesystem::exists(_path))
            {
                // 没有就创建
                try
                {
                    std::filesystem::create_directories(_path);
                }
                catch (const std::filesystem::filesystem_error &e)
                {
                    std::cerr << e.what() << '\n';
                }
            }
            // 不用判断是否有对应文件，写操作时没有的话自动创建
        }
        void LogSync(const std::string &message) override final
        {
            std::lock_guard<std::mutex> lock(_mtx);
            std::ofstream out(_file, std::ios::app);
            if (!out.is_open())
                return;
            out << message << gsep;

            out.close();
        }
        ~FileStrategy() = default;

    private:
        std::string _path;
        std::string _file_name;
        std::string _file;

        std::mutex _mtx;
    };
    // enum class LogLevel
    // {
    //     DEBUG,
    //     INFO,
    //     WARNING,
    //     ERROR,
    //     FATAL
    // };
    // std::string Level2Str(LogLevel level)
    // {
    //     switch (level)
    //     {
    //     case LogLevel::DEBUG:
    //         return "DEBUG";
    //     case LogLevel::INFO:
    //         return "INFO";
    //     case LogLevel::WARNING:
    //         return "WARNING";
    //     case LogLevel::ERROR:
    //         return "ERROR";
    //     case LogLevel::FATAL:
    //         return "FATAL";
    //     default:
    //         return "UNKNOWN";
    //     }
    // }

    std::string GetTimeStamp()
    {
        time_t t = time(nullptr);
        struct tm *local = localtime(&t);
        char buffer[32];
        strftime(buffer, 31, "%Y-%m-%d %H:%M:%S", local);
        return buffer;
    }

    class Log
    {
    public:
        // 构造函数，可以指定名称
        Log(const std::string &name = "default.log") : _name(name) {}

        void EnableConsoleSync()
        {
            _flush_strategy = std::make_unique<ConsoleStrategy>();
        }
        void EnableFileSync(const std::string &path = default_path)
        {
            _flush_strategy = std::make_unique<FileStrategy>(_name, path);
        }

        // 获取日志器名称
        const std::string &GetName() const { return _name; }

    private:
        struct LogMessage
        {
        public:
            LogMessage(/*const LogLevel level*/ const std::string &level, const std::string &file, const std::string &line, const Log &log)
                : _log(log)
            {
                std::stringstream ss;
                ss << '[' << GetTimeStamp() << "] " << '[' << level << "] " << '[' << getpid() << "] " << '[' << file << ':' << line << ']';
                _msg += ss.str();
            }
            template <typename T>
            LogMessage &operator<<(const T &t) // 修改bug，添加const属性
            {
                // 如果t是int的话，这样是不是就是不合法的，
                // 或者说这个引用指向的空间不存在？
                std::stringstream ss;
                ss << t;
                _msg += ss.str();
                return *this;
            }

            ~LogMessage()
            {
                _log._flush_strategy->LogSync(_msg);
            }

        private:
            std::string _msg;
            const Log &_log;
            std::mutex _mtx;
        };

    public:
        LogMessage operator()(const std::string level, const std::string name, int line)
        {
            return LogMessage(level, name, std::to_string(line), *this);
        }

    private:
        std::string _name;
        std::unique_ptr<LogStrategy> _flush_strategy;
    };

    // 日志管理器 - 支持多个命名日志器
    class LogManager
    {
    public:
        // C++11 Meyer's Singleton - 编译器保证线程安全
        static LogManager &Instance()
        {
            static LogManager instance; // C++11保证线程安全初始化
            return instance;
        }

        // 获取或创建命名日志器
        Log &GetLogger(const std::string &name = "default.log")
        {
            std::lock_guard<std::mutex> lock(_mtx);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                _loggers[name] = std::make_unique<Log>(name);
            }
            return *_loggers[name];
        }

        // 获取默认日志器
        Log &GetDefaultLogger()
        {
            return GetLogger("default");
        }

        // 如果对应的文件析构，同时删除相应管理的对象
        void erase(const std::string &name)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            _loggers.erase(name);
        }

    private:
        LogManager() = default;
        std::unordered_map<std::string, std::unique_ptr<Log>> _loggers;
        std::mutex _mtx;
    };

    // 便捷函数
    inline Log &GetLogger(const std::string &name = "default.log")
    {
        return LogManager::Instance().GetLogger(name);
    }

    // 默认全局日志器
    Log &logger = LogManager::Instance().GetDefaultLogger();

// 默认日志器,名称为default.log，默认打印文件在default.log
#define DLOG(level) GetLogger()(#level, __FILE__, __LINE__)
#define CONSOLESYNC() GetLogger().EnableConsoleSync()
#define DFILESYNC() GetLogger().EnableFileSync()

// 传入 file 和 path ,修改刷新策略
#define FILESYNC(file, path) GetLogger(file).EnableFileSync(path)
// 使用特定的日志生成器,没有则创建
#define LOG(file, level) GetLogger(file)(#level, __FILE__, __LINE__)
}
